package look.word.datasource.aop.datasource;

import lombok.extern.slf4j.Slf4j;
import look.word.datasource.config.DataSourceManagement;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import java.lang.reflect.Method;

@Component
@Aspect
@Slf4j
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class TargetDataSourceAspect {

    @Around("@within(TargetDataSource) || @annotation(TargetDataSource)")
    public Object beforeNoticeUpdateDataSource(ProceedingJoinPoint joinPoint) {
        TargetDataSource annotation = null;
        Class<? extends Object> target = joinPoint.getTarget().getClass();
        if (target.isAnnotationPresent(TargetDataSource.class)) {
            // 判断类上是否标注着注解
            annotation = target.getAnnotation(TargetDataSource.class);
            log.info("类上标注了注解");
        } else {
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            if (method.isAnnotationPresent(TargetDataSource.class)) {
                // 判断方法上是否标注着注解，如果类和方法上都没有标注，则报错
                annotation = method.getAnnotation(TargetDataSource.class);
                log.info("方法上标注了注解");
            } else {
                throw new RuntimeException("@TargetDataSource注解只能用于类或者方法上, 错误出现在:[" +
                        target.toString() + " " + method.toString() + "];");
            }
        }
        // 切换数据源
        DataSourceManagement.flag.set(annotation.value().name());
        log.info("【切换到数据源：{}】", annotation.value().name());
        Object result = null;
        try {
            // 执行目标代码
            result = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return result;
    }
}
